/**
 * @FileName: CmccRechargeService.java
 * @Author
 * @Description:
 * @Date 2016年5月26日 上午9:33:03
 * @CopyRight ZTE Corporation
 */
package cn.hpclub.server.service;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.hpclub.server.ccbpay.ServiceType;
import cn.hpclub.server.model.RechargeOrder;
import cn.hpclub.server.plugin.Ssdb;

public class CmccRechargeService{
    private static final Logger       logger   = LoggerFactory.getLogger(CmccRechargeService.class);
    private static final int          NOT_PAID = 0;

    private static final int          PAID     = 1;

    private static final int          FAILED   = 2;

    public static CmccRechargeService service  = new CmccRechargeService();

    public synchronized boolean updateRechargeOrder(String orderId, String amount, boolean result){
        logger.info("pay result = " + result);
        boolean canRecharge = false;
        try{
            // 支付状态：0-未支付 1-支付成功，2-支付失败
            int payStatus = result ? PAID : FAILED;
            RechargeOrder order = RechargeOrder.dao.getRechargeOrderByOrderId(orderId);
            if(order != null){
                logger.info("******recharge_phone = " + order.getStr(RechargeOrder.RECHARGE_PHONE));
                logger.info("******pay_amount = " + amount);
                if(order.getInt(RechargeOrder.PAY_STATUS) != PAID){
                    logger.info("first time suc");
                    Date currDate = new Date();
                    order.set(RechargeOrder.PAY_AMOUNT, Double.valueOf(amount));
                    order.set(RechargeOrder.PAY_STATUS, payStatus);
                    order.set(RechargeOrder.PAY_TIME, currDate);
                    order.set(RechargeOrder.OPERATED_TIME, currDate);
                    order.set(RechargeOrder.OPERATED_DESC, "更新支付状态");
                    // db状态为未支付，当前通知为已支付，即成功支付的第一次回调，写数据库成功后就进行充值。写数据库失败，也不充值，以免后续又有回调，导致充值两次。
                    if(payStatus == PAID){
                        logger.info("******pay success");
                        canRecharge = order.update();
                    } else if(payStatus == FAILED){
                        // 回调为支付失败，则仅更新数据库，不充值。
                        logger.info("******pay failed");
                        order.update();
                    }

                }
            }

        }
        catch(Exception e){
            logger.error("update recharge order exception，order ID:" + orderId + ",amount:" + amount + ",result:"
                    + result);
            canRecharge = false;
            e.printStackTrace();
        }
        finally{
            saveSsdb(ServiceType.RECHARGE, orderId, amount, result);
        }
        // 更新出现异常时，请返回false
        logger.info("rechargeOrder canRecharge = " + canRecharge);
        return canRecharge;

    }

    private void saveSsdb(ServiceType type, String orderId, String amount, boolean result){
        try{
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
            String dateString = simpleDateFormat.format(new Date());

            SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("hh:mm:ss");
            String timeString = simpleDateFormat2.format(new Date());

            Map<String, String> infos = new HashMap<>();
            infos.put("no", orderId);
            infos.put("total", amount);
            infos.put("status", result ? "Y" : "N");
            infos.put("time", timeString);
            if(type == ServiceType.RECHARGE){
                Ssdb.use().hset("recharge" + dateString, orderId, infos);
            } else if(type == ServiceType.PACKAGE){
                Ssdb.use().hset("package" + dateString, orderId, infos);
            }
        }
        catch(Exception e){
            logger.error("save pay record to ssdb failed.service type:" + type + ",orderid:" + orderId + ",amount:"
                    + amount + ",result:" + result);
            e.printStackTrace();
        }

    }

    /**
     * @Title: updateRechargeOrderNew
     * @Description:建行支付完回来更新支付状态、支付金额等
     * @param orderId
     * @param amount
     * @param result
     * @return boolean
     */
    public boolean updateRechargeOrderNew(String orderId, String amount, boolean result){
        boolean canRecharge = false;
        try{
            // 支付状态：0-未支付 1-支付成功，2-支付失败
            int payStatus = result ? RechargeOrder.PAID : RechargeOrder.FAILED;
            if(payStatus == RechargeOrder.PAID){
                // 支付成功
                // 未付/失败->成功，写DB(写DB失败，不办理业务，以免后续多次办理业务)，写成功，若金额相同，办理业务，金额不同，则不办理业务；成功->成功，不写DB，不办理业务。

                // 利用DB进行同步控制。多个notify只有一个会去写数据库。
                canRecharge = RechargeOrder.dao.updatePayStatusSuc(orderId, payStatus, new Date(), "支付成功",
                                                                   Double.valueOf(amount));
                // 互斥的情况下，保证同一个orderid只有一个notify会去判断金额是否正确。
                if(canRecharge){
                    logger.info("recharge first time suc-msg");
                    // 若是金额不同，执行完上面的更新表格后，返回false，不去办理业务。避免被攻击办理了业务。
                    if(amountIncorrect(orderId, amount, canRecharge)){
                        canRecharge = false;
                    }

                } else{
                    // 已办理过业务
                    logger.info("recharge business already done");
                }

            } else{
                // 未付->失败，写DB，不论写DB成功与否，都不办业务；失败->失败，不写DB,不办业务；成功->失败，不写DB，不办业务，以免成功-失败-成功，导致多次办理业务。
                logger.info("recharge pay failed.order:" + orderId);
                RechargeOrder.dao.updatePayStatusFailed(orderId, payStatus, new Date(), "支付失败", Double.valueOf(amount));
                canRecharge = false;
            }

        }
        catch(Exception e){
            logger.error("update recharge order exception，order ID:" + orderId + ",amount:" + amount + ",result:"
                    + result);
            // 更新出现异常时，请返回false
            canRecharge = false;
            e.printStackTrace();
        }
        finally{
            // 不管成功还是失败，都写SSDB，保存原始记录。
            saveSsdb(ServiceType.RECHARGE, orderId, amount, result);
        }

        logger.info("updateRechargeOrder canRecharge = " + canRecharge);
        return canRecharge;
    }

    /**
     * @Title: amountIncorrect
     * @Description:判断建行支付金额是否和充值金额不一致
     * @param orderId
     * @param amount
     * @param canRecharge
     * @return boolean
     */
    private boolean amountIncorrect(String orderId, String amount, boolean canRecharge){
        RechargeOrder order = RechargeOrder.dao.getRechargeOrderByOrderId(orderId);
        Double orderAmount = order.getDouble(RechargeOrder.RECHARGE_MONEY);
        Double paidAmount = Double.valueOf(amount);
        logger.info("recharge -> orderid:" + orderId + ",orderAmount:" + orderAmount + ",paidAmount:" + paidAmount);
        if(Double.compare(paidAmount, orderAmount) < 0){
            logger.error("recharge paid error.amount is not corrent." + "orderid:" + orderId + ",orderAmount:"
                    + orderAmount + ",paidAmount:" + paidAmount);
            return true;
        }
        return false;
    }

}
